{
 "cells": [
  {
   "cell_type": "markdown",
   "source": [
    "# MBQC 入门介绍 \n",
    "\n",
    "<em> Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved. </em>"
   ],
   "metadata": {
    "tags": []
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 概述\n",
    "\n",
    "量子计算利用量子世界中特有的运行规律，为我们提供了一种全新的并且非常有前景的信息处理方式。其计算的本质是通过特定的方式将初始制备的量子态演化成我们预期的另一个量子态，然后在演化后的量子态上做测量以获得计算结果。但是在不同模型下，量子态的演化方式各异。比较常用的**量子电路模型 (quantum circuit model)** [1,2] 通过对量子态进行量子门操作来完成演化，该模型可以理解为经典计算模型的量子版本，被广泛地应用在量子计算领域中。而**基于测量的量子计算 （measurement-based quantum computation, MBQC)** 是一种完全不同于量子电路模型的计算方式。\n",
    "\n",
    "顾名思义，MBQC 模型的计算过程是通过量子测量完成的。基于测量的量子计算主要有两种子模型：**隐形传态量子计算 (teleportation-based quantum computing, TQC)** 模型 [3-5]\n",
    "和**单向量子计算机 (one-way quantum computer, 1WQC)** 模型\n",
    "[6-9]。其中，前者需要用到多量子比特的联合测量，而后者只需要单比特测量即可。有趣的是，这两种子模型在被分别提出后，被证明是高度相关并且一一对应的 [10]。所以我们此后将不加声明地，**默认讨论的 MBQC 模型为 1WQC 模型。**\n",
    "\n",
    "与电路模型不同，MBQC 是量子计算特有的一种模型，没有经典计算模型的对应。该模型的核心思想在于对一个量子纠缠态的部分比特进行测量，未被测量的量子系统将会实现相应的演化，并且通过对测量方式的控制，我们可以实现任意需要的演化。MBQC\n",
    "模型下的计算过程主要分为三个步骤：第一步，准备一个**资源态 (resource state)**，即一个高度纠缠的多体量子态，该量子态可以在计算开始之前准备好，且可以与具体计算任务无关；第二步，对准备好的资源态的每个比特依次做单比特测量，其中后续比特的测量方式可以根据已经被测量的比特的测量结果做出相应调整，即允许**适应性测量 (adaptive measurement)**；第三步，对测量后得到的量子态进行 **副产品纠正 (byproduct correction)**。最后，我们对所有比特的测量结果进行经典数据处理，即可得到需要的计算结果。\n",
    "\n",
    "图 1 给出了一个 MBQC 模型下的算法示例。图中的网格代表了一种常用的量子资源态，（称为**团簇态，cluster state**，详见下文），网格上的每个节点都代表了一个量子比特，整个网格则代表了一个高度纠缠的量子态。我们依次对每个比特进行测量（节点中的 $X, Y, Z, XY$ 等表示对应的测量基），对测量后的量子态进行副产品纠正（消除 Pauli $X$ 算符和 Pauli $Z$ 算符），即可完成计算。\n",
    "\n",
    "![MBQC example](./figures/mbqc-fig-general_pattern.jpg)\n",
    "<div style=\"text-align:center\">图 1: 通过对网格上的每个比特进行测量来完成计算 </div>\n",
    "\n",
    "MBQC 模型的计算方式给我们带来了诸多好处。比如说，如果第一步制备的量子态噪声太大，我们则可以**在计算开始之前（即测量之前)**\n",
    "丢弃这个态，并重新制备，以此保证计算结果的准确性；由于资源态可以与计算任务无关，因此可以应用在安全代理计算中 [11,\n",
    "12]，保护计算的隐私；另外，单比特量子测量在实验上比量子门更容易实现，保真度更高，并且无适应性依赖关系的量子测量可以同步进行，从而降低整个计算的深度，对量子系统相干时间要求更低。MBQC\n",
    "模型实现上的技术难点主要在于第一步资源态的制备，该量子态高度纠缠，并且制备所需的比特数比通常电路模型的多很多。关于资源态制备的相关进展，有兴趣的读者可以参见 [13,14] 。表格 1 概括了 MBQC 模型与量子电路模型的优势和限制。\n",
    "\n",
    "|    | 量子电路模型     | 基于测量的量子计算模型    |\n",
    "|:---: | :---: | :---: |\n",
    "| 优势|  与经典计算模型对应 <br/>易于理解和拓展应用 | 资源态可与计算无关 <br/> 单比特测量易于操作 <br/> 可并行测量，算法深度低 |\n",
    "|限制| 量子门执行顺序固定 <br/> 电路深度受相干时间限制| 无经典对应，不直观 <br/> 资源态比特数多，制备难度高 | \n",
    "\n",
    "<div style=\"text-align:center\">表 1：基于测量的量子计算模型与量子电路模型的优势和限制比较 </div>\n",
    "\n",
    "MBQC 模型因为没有经典对应，初学者可能有些难以用直觉去理解，但也正是这种超乎直觉的计算方式，给该模型带来了更多探索的空间和无穷的乐趣。接下来，就让我们共同走进 MBQC 模型的世界，一起来探索其中的奥秘吧！"
   ],
   "metadata": {
    "tags": []
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 预备知识\n",
    "\n",
    "在正式介绍 MBQC 模型以及我们的模块之前，我们首先回顾一下掌握 MBQC 模型需要用到的两个核心知识点。\n",
    "\n",
    "### 1. 图与图态\n",
    "    \n",
    "对于任意给定一个图 $G=(V, E)$，其中，$V$ 是点的集合，$E$ 是边的集合，我们可以定义一个量子态与之对应。具体的做法为，将图 $G$ 中每个节点对应一个加态 $|+\\rangle = (|0\\rangle +\n",
    "|1\\rangle) / \\sqrt{2}$，如果图中两个节点之间有边相连，则将对应节点上的加态之间作用控制 Z 门， $CZ = |0\\rangle\\langle0| \\otimes I +\n",
    "|1\\rangle\\langle1|\\otimes Z$。由此步骤生成的量子态称为图 $G$ 的**图态 (graph state)**，记为 $|G\\rangle$，具体数学表达式如下：\n",
    "    \n",
    "$$\n",
    "|G\\rangle = \\prod_{(a,b) \\in E} CZ_{ab} \\left(\\bigotimes_{v \\in V}|+\\rangle_v\\right). \\tag{1}\n",
    "$$\n",
    "\n",
    "图态其实并不是一个陌生的概念。通过局部的酉变换，我们所熟知的 Bell 态、GHZ 态等都可以表示为一个图对应的图态；此外，如果我们考虑的图具有周期网状的晶格结构（简单理解为二维坐标系的网格图），那么其对应的图态称为**团簇态 (cluster state)**，如图 2 所示。\n",
    "\n",
    "![Graph states](./figures/mbqc-fig-graph_states.jpg)\n",
    "<div style=\"text-align:center\">图 2：图 (i) 对应的图态为 $Bell$ 态，图 (ii) 对应的图态为一个 4-qubit 的 $GHZ$ 态，图 (iii) 对应一个团簇态 </div>\n",
    "\n",
    "\n",
    "### 2. 投影测量\n",
    "\n",
    "量子测量是量子信息处理中的核心概念之一，在电路模型中，量子测量往往出现在电路末端，用于从量子态中解码出我们需要的经典结果。但是在 MBQC 模型中，量子测量不仅用于解码算法答案，还用于控制量子态的演化过程，即：通过对纠缠的多体量子态进行部分测量，驱动未测量的量子态进行演化。在 MBQC 模型中，我们默认使用单比特测量，且以 0/1 投影测量为主。根据测量公理 [17]，假设待测量的量子态为 $|\\phi\\rangle$，投影测量由一对正交基 $\\{|\\psi_0\\rangle, |\\psi_1\\rangle\\}$ 给出，那么测量结果为 $s \\in \\{0,1\\}$ 的概率为 $p(s) = |\\langle \\psi_s|\\phi\\rangle|^2$，测量后对应的量子态坍缩为 $|\\psi_s\\rangle\\langle\\psi_s|\\phi\\rangle / \\sqrt{p(s)}$，即被测量的比特坍缩为 $|\\psi_s\\rangle$，其他比特演化为 $\\langle\\psi_s|\\phi\\rangle / \\sqrt{p(s)}$。\n",
    "\n",
    "特别地，我们常用到的单比特测量为 $XY$, $YZ$, $XZ$ 三个平面上的投影测量，它们分别由如下的正交基给出，\n",
    "\n",
    "- XY 平面测量：$M^{XY}(\\theta) = \\{R_z(\\theta) |+\\rangle, R_z(\\theta) |-\\rangle \\}$，其中，当 $\\theta = 0$ 时为 $X$ 测量；当 $\\theta = \\frac{\\pi}{2}$ 时为 $Y$ 测量；\n",
    "\n",
    "- YZ 平面测量：$M^{YZ}(\\theta) = \\{R_x(\\theta)|0\\rangle, R_x(\\theta)|1\\rangle\\}$，其中，当 $\\theta = 0$ 时为 $Z$ 测量；\n",
    "\n",
    "- XZ 平面测量：$M^{XZ}(\\theta) = \\{R_y(\\theta)|0\\rangle, R_y(\\theta)|1\\rangle\\}$，其中，当 $\\theta = 0$ 时为 $Z$ 测量；\n",
    "\n",
    "以上 $|+\\rangle = (|0\\rangle + |1\\rangle)/ \\sqrt{2},|-\\rangle = (|0\\rangle - |1\\rangle)/ \\sqrt{2}$, 且 $R_x, R_y, R_z$ 分别为绕 $x,y,z$ 轴旋转的单比特旋转门。"
   ],
   "metadata": {
    "tags": []
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 框架介绍\n",
    "\n",
    "\n",
    "### 1. 技术路线及代码实现\n",
    "\n",
    "#### “三步走”流程\n",
    "\n",
    "前面提到，MBQC 模型不同于常见的量子电路模型，该模型中量子态的演化是通过对量子图态上的部分比特进行测量来实现的。具体地，MBQC 模型由以下三个步骤构成。\n",
    "\n",
    "- **量子图态准备**：即准备一个多体纠缠态。一般地，我们给出图（点和边）的信息，初始化图中节点为加态，根据图中节点的连线方式作用控制 Z 门，便可以生成量子图态。以此对应关系，每当我们给定一个图的信息，我们便可以在其上定义对应的量子图态。此外，我们还可以根据需要选择性替换图态中某些节点上的加态为指定的输入态。\n",
    "- **单比特测量**：按照特定的测量方式对上一步准备好的量子图态进行单比特测量，测量角度可以根据已获得的测量结果进行动态调整。无适应性依赖关系的测量可以交换顺序或同时进行。\n",
    "- **副产品纠正**：由于测量结果的随机性，未测量量子态的演化方式不能唯一确定，换句话说，未测量的量子态有可能会进行一些多余的演化。我们称这些多余的演化为**副产品（byproduct\n",
    "）**。因而算法的最后一步就是对副产品进行纠正，得到我们预期的演化结果。如果算法最后要求输出的不是一个量子态，而是对演化完的量子态继续进行测量并获取经典结果的话，副产品的影响只需要通过经典数据处理来修正即可。因此，MBQC\n",
    "模型的主要步骤为前两步，第三步是否进行则是取决于我们想要获得的是量子态的输出还是测量结果的经典输出。\n",
    "\n",
    "依次进行上述三个步骤，我们可以概括出 MBQC 模型“三步走”的流程，即：量子图态准备、单比特测量和副产品纠正。\n",
    "\n",
    "#### 测量模式与 \"EMC\" 语言\n",
    "\n",
    "除了常用的“三步走”流程之外，一个 MBQC 模型还可以用 \"EMC\" 语言 [18] 来描述。如前所述，MBQC 模型与电路模型具有一一对应关系。我们可以把由电路模型对应的 MBQC 模型称为该电路模型的测量**模式 (pattern)** ，把电路中的单个量子门或对输出态的单个测量对应的 MBQC 模型称为该量子门或测量对应的**子模式 (subpattern)** [18]。在描述 MBQC 的 \"EMC\" 语言中，我们将纠缠操作对应 “纠缠命令”，用符号 \"E\" 来表示；将测量操作对应 “测量命令”，用符号 \"M\" 来表示；将副产品纠正操作对应 “副产品纠正命令”，用符号 \"C\" 来表示。于是，对应于上述“三步走”流程，一个完整的 MBQC 运算过程还可以用“命令列表” \\[EMC\\] 来表示。运算过程则是按照命令列表从左至右的顺序执行各个命令。为了让大家快速地熟悉 MBQC 模型，在本教程中，我们采用经典的“三步走”流程来描述 MBQC 模型的运算过程。\n",
    "\n",
    "#### 代码实现\n",
    "\n",
    "代码实现上，我们将模拟 MBQC 模型的过程整合为一个模块 ``simulator``，该模块的主要内容是 ``MBQC`` 类，该类具有与 MBQC 模型相关的属性和类方法。我们可以根据具体情况自行实例化 MBQC 类，从而建立并模拟对应的 MBQC 模型算法。\n",
    "\n",
    "```python\n",
    "# 代码实现\n",
    "from paddle_quantum.mbqc.simulator import MBQC\n",
    "\n",
    "class MBQC:\n",
    "    def __init__():\n",
    "        ...\n",
    "```\n",
    "\n",
    "实例化 MBQC 类之后，我们通过依次调用相关类方法就可以完成 MBQC 模型的运算过程。接下来我们通过一个表格（如表 2 所示）简单介绍一下常用的类方法及其功能。更为详细和全面的介绍请参考相关 API 文档。\n",
    "\n",
    "|类方法|功能|\n",
    "|:---:|:---:|\n",
    "|set_graph|输入图的信息|\n",
    "|set_pattern|输入测量模式的信息|\n",
    "|set_input_state|输入初始量子态的信息|\n",
    "|draw_process|画出 MBQC 模型运算过程的动态图|\n",
    "|track_progress|查看 MQBC 模型运算的进度条|\n",
    "|measure|执行单比特测量|\n",
    "|sum_outcomes|对指定节点的测量结果进行求和|\n",
    "|correct_byproduct|纠正副产品|\n",
    "|run_pattern|运行测量模式|\n",
    "|get_classical_output|获取经典输出结果|\n",
    "|get_quantum_output|获取量子输出结果|\n",
    "\n",
    "<div style=\"text-align:center\">表 2：MBQC 类中常用的类方法及其功能 </div>\n",
    "\n",
    "在 MBQC 模拟模块中，为了方便大家使用，我们设置了“图”（graph）和“模式”（pattern）的两种输入方式，分别对应于 MBQC 模型运算过程的两种描述方式。如果输入为图，则后续运算过程需要我们自行按照“三步走”流程完成。值得一提的是，我们设计了**节点动态分类算法**来模拟 MBQC 的运算过程，简单来说，就是将 MBQC “三步走”流程中的第一、二步进行整合，交换某些纠缠和测量操作，从而降低实际参与运算的比特数，提高运算效率。MBQC 模拟模块具体调用格式如下：\n",
    "\n",
    "```python\n",
    "\"\"\"\n",
    "MBQC 模拟模块调用格式（以图为输入，进行“三步走”流程）\n",
    "\"\"\"\n",
    "from paddle_quantum.mbqc.simulator import MBQC\n",
    "\n",
    "# 实例化 MBQC 类创建一个模型\n",
    "mbqc = MBQC()\n",
    "\n",
    "# “三步走”中第一步，设置图\n",
    "mbqc.set_graph(graph)\n",
    "\n",
    "# 设置初始态 （可选）\n",
    "mbqc.set_input_state(input_state)\n",
    "\n",
    "# “三步走”中第二步，单比特测量\n",
    "mbqc.measure(which_qubit, basis)\n",
    "mbqc.measure(which_qubit, basis)\n",
    "......\n",
    "\n",
    "# “三步走”中第三步，纠正副产品\n",
    "mbqc.correct_byproduct(gate, which_qubit, power)\n",
    "\n",
    "# 输出运行后的经典和量子输出结果\n",
    "classical_output = mbqc.get_classical_output()\n",
    "quantum_output = mbqc.get_quantum_output()\n",
    "```\n",
    "\n",
    "如果输入为测量模式，只需调用 `run_pattern` 类方法即可完成 MBQC 模型运算过程，格式如下：\n",
    "\n",
    "```python\n",
    "\"\"\"\n",
    "MBQC 模拟模块调用格式（以测量模式为输入，执行 \"EMC\" 命令）\n",
    "\"\"\"\n",
    "from paddle_quantum.mbqc.simulator import MBQC\n",
    "\n",
    "# 实例化 MBQC 类创建一个模型\n",
    "mbqc = MBQC()\n",
    "\n",
    "# 设置测量模式\n",
    "mbqc.set_pattern(pattern)\n",
    "\n",
    "# 设置初始态 （可选）\n",
    "mbqc.set_input_state(input_state)\n",
    "\n",
    "# 运行测量模式\n",
    "mbqc.run_pattern()\n",
    "\n",
    "# 输出运行后的经典和量子输出结果\n",
    "classical_output = mbqc.get_classical_output()\n",
    "quantum_output = mbqc.get_quantum_output()\n",
    "```"
   ],
   "metadata": {
    "tags": []
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "跟据前面的介绍，相信大家对 MBQC 模型以及我们设计的 MBQC 模拟模块有了大致的了解。下面我们用两个示例带领大家进行一些实战。"
   ],
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": [
    "### 2. 使用示例：用 MBQC 实现任意单比特量子门\n",
    "\n",
    "跟据量子门的分解，我们知道任意单比特量子门 $U$ 都可以分解为 $ U = R_x(\\gamma)R_z(\\beta)R_x(\\alpha)$ 的形式（忽略全局相位）[17] 。在 MBQC 模型中，这样的单比特量子门可以按如下的方式实现（参见图 3） [15] ：准备五个量子比特，最左侧是输入比特，最右侧为输出比特。输入量子态 $|\\psi\\rangle$，其余量子比特初始化为加态，相邻比特作用控制 Z 门，对第一个比特作 $X$ 测量，对中间三个比特依次进行适应性测量，前四个比特的测量结果依次记为 $s_1$, $s_2$, $s_3$, $s_4$，根据测量结果对得到的量子态进行副产品修正，则在第五个比特上输出的结果为 $U|\\psi\\rangle$。\n",
    "\n",
    "![Single qubit pattern](./figures/mbqc-fig-single_qubit_pattern_CN.jpg)\n",
    "<div style=\"text-align:center\">图 3: MBQC 模型下任意单比特量子门的实现方式 </div>\n",
    "\n",
    "**注意**：测量完前四个比特后，第五个量子比特的状态为 $X^{s_2 + s_4}Z^{s_1 + s_3} U|\\psi\\rangle$，其中 $X^{s_2 + s_4}Z^{s_1 + s_3}$ 就是所谓的副产品，我们需要跟据测量结果，对此进行修正，才能得到想要的 $U|\\psi\\rangle$。\n",
    "\n",
    "以下是代码展示："
   ],
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": [
    "#### 引入计算所需要的模块\n",
    "\n",
    "一方面，我们需要引入 `numpy` 和 `paddle` 两个常用的计算模块；另一方面，我们需要引入 MBQC 模拟的相关模块，其中 `simulator` 为模拟的核心模块，主要包含 `MBQC` 类，我们可以实例化这个类，搭建属于自己的 MBQC 模型；`qobject` 包含量子信息处理常用的量子对象（如：`State`,`Circuit`,`Pattern`等）；`utils` 包含计算所需要的常用函数（如：`plus_state` 加态，`basis` 常用测量基等）。"
   ],
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "source": [
    "# 引入常用的计算模块\n",
    "from numpy import pi\n",
    "from paddle import to_tensor, matmul\n",
    "# 引入 MBQC 模拟相关模块\n",
    "from paddle_quantum.mbqc.simulator import MBQC\n",
    "from paddle_quantum.mbqc.qobject import State\n",
    "from paddle_quantum.mbqc.utils import rotation_gate, basis, random_state_vector, compare_by_vector"
   ],
   "outputs": [],
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": [
    "#### 输入图和量子态\n",
    "\n",
    "接下来，我们可以自定义要输入的图，在此例中，如图 $3$ 所示，我们需要输入的是五个带标签的节点（记作 `['1', '2', '3', '4', '5']` ）和图中的四条边（记作 `[('1', '2'), ('2', '3'), ('3', '4'), ('4', '5')]` ），并在最左侧的比特 `'1'` 上输入量子态，同时初始化测量的角度。"
   ],
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "source": [
    "# 构造用于 MBQC 计算的图\n",
    "V = ['1', '2', '3', '4', '5']\n",
    "E = [('1', '2'), ('2', '3'), ('3', '4'), ('4', '5')]\n",
    "G = [V, E]\n",
    "# 生成一个随机的量子态向量\n",
    "input_psi = random_state_vector(1)\n",
    "# 用量子态向量和系统标签，在第一个节点上构造一个量子态\n",
    "input_state = State(input_psi, ['1'])\n",
    "# 初始化角度，注意为 Tensor 形式\n",
    "alpha = to_tensor([pi / 6], dtype='float64')\n",
    "beta  = to_tensor([pi / 4], dtype='float64')\n",
    "gamma = to_tensor([pi / 3], dtype='float64')"
   ],
   "outputs": [],
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": [
    "#### 初始化 MBQC 模型\n",
    "\n",
    "实例化 `MBQC` 类并设置图和输入量子态的信息，就可以搭建属于自己的 MBQC 模型了。"
   ],
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "source": [
    "# 实例化 MBQC 类\n",
    "mbqc = MBQC()\n",
    "# 输入图的信息\n",
    "mbqc.set_graph(G)\n",
    "# 输入初始量子态的信息\n",
    "mbqc.set_input_state(input_state)"
   ],
   "outputs": [],
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": [
    "之后，我们依次对四个节点进行测量。"
   ],
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": [
    "####  测量第一个节点\n",
    "\n",
    "根据图 3，第一个比特的测量方式为 $X$ 测量，也就是 $XY$ 平面测量角度为 $0$ 的情形，即 $\\theta_1 = 0$。 "
   ],
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "source": [
    "# 计算第一个比特的测量角度\n",
    "theta1 = to_tensor([0], dtype='float64')\n",
    "# 对第一个比特进行测量\n",
    "mbqc.measure('1', basis('XY', theta1))"
   ],
   "outputs": [],
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": [
    "第一个比特的测量不涉及适应性的问题，所以比较简单，但对于第二、三和四个比特而言，其测量角度就需要考虑前面的测量结果了。"
   ],
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": [
    "#### 测量第二个节点\n",
    "\n",
    "根据图 3，第二个比特的测量方式为 $M^{XY}(\\theta_2)$ 测量，其中，\n",
    "\n",
    "$$\n",
    "\\theta_2 = (-1)^{s_1 + 1} \\alpha, \\tag{2}\n",
    "$$\n",
    "\n",
    "也就是 $XY$ 平面测量角度为 $(-1)^{s_1 + 1} \\alpha$ 的测量，其中 $s_1$ 为第一个节点的测量结果。 \n",
    "\n",
    "在 `MBQC` 类中，我们定义了类方法 `sum_outcomes` ，可以对指定输入标签的量子比特的测量结果进行求和运算，如果想要对求和结果额外加上一个数字 $x$，则可在第二个参数处赋值 $x$，否则为 $0$。"
   ],
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "source": [
    "# 计算第二个比特的测量角度\n",
    "theta2 = to_tensor((-1) ** mbqc.sum_outcomes(['1'], 1), dtype='float64') * alpha\n",
    "# 对第二个比特进行测量\n",
    "mbqc.measure('2', basis('XY', theta2))"
   ],
   "outputs": [],
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": [
    "#### 测量第三个节点\n",
    "\n",
    "根据图 3，第三个比特的测量方式为 $M^{XY}(\\theta_3)$ 测量，其中，\n",
    "\n",
    "$$\n",
    "\\theta_3 = (-1)^{s_2 + 1} \\beta, \\tag{3}\n",
    "$$\n",
    "\n",
    "也就是 $XY$ 平面测量角度为 $(-1)^{s_2 + 1} \\beta$ 的测量，其中 $s_2$ 为第二个节点的测量结果。 "
   ],
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "source": [
    "# 计算第三个比特的测量角度\n",
    "theta3 = to_tensor((-1) ** mbqc.sum_outcomes(['2'], 1), dtype='float64') * beta\n",
    "# 对第三个比特进行测量\n",
    "mbqc.measure('3', basis('XY', theta3))"
   ],
   "outputs": [],
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": [
    "#### 测量第四个节点\n",
    "\n",
    "根据图 3，第四个比特的测量方式为 $M^{XY}(\\theta_4)$ 测量，其中，\n",
    "\n",
    "$$\n",
    "\\theta_4 = (-1)^{s_1 + s_3 + 1} \\gamma, \\tag{4}\n",
    "$$\n",
    "\n",
    "也就是 $XY$ 平面测量角度为 $(-1)^{s_1 + s_3 + 1} \\gamma$ 的测量，其中 $s_1$ 为第一个节点的测量结果，其中 $s_3$ 为第三个节点的测量结果。 "
   ],
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "source": [
    "# 计算第四个比特的测量角度\n",
    "theta4 = to_tensor((-1) ** mbqc.sum_outcomes(['1', '3'], 1), dtype='float64') * gamma\n",
    "# 对第四个比特进行测量\n",
    "mbqc.measure('4', basis('XY', theta4))"
   ],
   "outputs": [],
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": [
    "#### 对第五个节点输出的量子态进行修正\n",
    "\n",
    "前四个节点测量结束之后，第五个节点上的输出量子态并不是 $U|\\psi\\rangle$，而是附带有副产品的量子态 $X^{s_2 + s_4}Z^{s_1 + s_3} U|\\psi\\rangle$， 如果希望输出量子态为 $U|\\psi\\rangle$，需要在测量结束之后对副产品进行修正。"
   ],
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "source": [
    "# 对量子态的副产品进行修正\n",
    "mbqc.correct_byproduct('X','5', mbqc.sum_outcomes(['2','4']))\n",
    "mbqc.correct_byproduct('Z','5', mbqc.sum_outcomes(['1','3']))"
   ],
   "outputs": [],
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": [
    "####  读取修正后的量子态并与预期的量子态进行比较\n",
    "\n",
    "调用 `get_classical_output` 和 `get_quantum_output` 分别获取经典和量子输出结果。为了方便检验修正之后的量子态是否为我们预期的单比特量子门演化后的量子态 $U|\\psi\\rangle$，我们在 `utils` 模块中定义了两种比较两个量子态是否相同的函数 `compare_by_vector` 和 `compare_by_density`，前者是通过量子态列向量进行比较，后者是将量子态转化为密度矩阵进行比较。实际使用的时候，我们可以根据自己的需求调用这两个函数。若两个量子态相同，则该函数输出误差范数，并打印 \"They are exactly the same states.\" 字样。（注意：我们默认误差范数在 1e-14 到 1e-16 之间的两个量子态为同一量子态。）"
   ],
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "source": [
    "# 读取经典输出结果\n",
    "classical_output = mbqc.get_classical_output()\n",
    "# 读取量子输出结果\n",
    "quantum_output = mbqc.get_quantum_output()\n",
    "\n",
    "# 计算预期的量子态列向量\n",
    "vector_std = matmul(rotation_gate('x', gamma),\n",
    "                matmul(rotation_gate('z', beta),\n",
    "                    matmul(rotation_gate('x', alpha), input_psi)))\n",
    "# 构造预期的量子态\n",
    "state_std = State(vector_std, ['5'])\n",
    "\n",
    "# 与预期的输出态进行比较\n",
    "compare_by_vector(quantum_output, state_std)"
   ],
   "outputs": [],
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": [
    "### 3. 使用示例： 用 MBQC 实现 CNOT 门\n",
    "\n",
    "CNOT 门是电路模型中常用的两比特门，在 MBQC 模型中， CNOT 门的实现方案如下（参见图 4） [7]：准备 $15$ 个量子比特，第 $1$、$9$ 比特是输入比特，最右侧 $7$ 和 $15$ 为输出比特。输入量子态 $|\\psi\\rangle$，其余量子比特初始化为加态，图中相连接的比特作用控制 Z 门。对第 $1, 9, 10, 11, 13, 14$ 做 $X$ 测量，对 $2, 3, 4, 5, 6, 8, 12$ 做 $Y$ 测量（注意：这些测量的角度无依赖关系，交换测量顺序对测量结果没有影响），对副产品算符进行修正后，在 $7$ 和 $15$ 输出的量子比特将会为 $\\text{CNOT}|\\psi\\rangle$。\n",
    "\n",
    "![CNOT pattern](./figures/mbqc-fig-cnot_pattern.jpg)\n",
    "<div style=\"text-align:center\">图 4: MBQC 模型下 CNOT 门的一种实现方式 </div>\n",
    "\n",
    "**注意**：与前面的单比特量子门类似，我们需要在测量完之后对副产品进行修正才能得到预期的 $\\text{CNOT}|\\psi\\rangle$。\n",
    "\n",
    "以下是完整的代码展示："
   ],
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "source": [
    "# 引入常用的计算模块\n",
    "from paddle import to_tensor, matmul\n",
    "# 引入 MBQC 模拟相关模块\n",
    "from paddle_quantum.mbqc.simulator import MBQC\n",
    "from paddle_quantum.mbqc.qobject import State\n",
    "from paddle_quantum.mbqc.utils import pauli_gate, cnot_gate, basis, random_state_vector, compare_by_vector\n",
    "\n",
    "# 定义 X 门和 Z 门，X 测量和 Z 测量\n",
    "X = pauli_gate('X')\n",
    "Z = pauli_gate('Z')\n",
    "X_basis = basis('X')\n",
    "Y_basis = basis('Y')\n",
    "\n",
    "# 定义用于 MBQC 计算的图\n",
    "V = [str(i) for i in range(1, 16)]\n",
    "E = [('1', '2'), ('2', '3'), ('3', '4'), ('4', '5'), \n",
    "     ('5', '6'), ('6', '7'), ('4', '8'), ('8', '12'),\n",
    "     ('9', '10'), ('10', '11'), ('11', '12'), \n",
    "     ('12', '13'), ('13', '14'), ('14', '15')]\n",
    "G = [V, E]\n",
    "\n",
    "# 生成一个随机的量子态列向量\n",
    "input_psi = random_state_vector(2)\n",
    "# 用量子态向量和系统标签，在指定节点上构造一个量子态\n",
    "input_state = State(input_psi, ['1','9'])\n",
    "\n",
    "# 初始化 MBQC 类\n",
    "mbqc = MBQC()\n",
    "# 输入图的信息\n",
    "mbqc.set_graph(G)\n",
    "# 输入初始量子态的信息\n",
    "mbqc.set_input_state(input_state)\n",
    "\n",
    "# 依次对节点进行测量，注意以下测量顺序可以任意交换\n",
    "mbqc.measure('1', X_basis)\n",
    "mbqc.measure('2', Y_basis)\n",
    "mbqc.measure('3', Y_basis)\n",
    "mbqc.measure('4', Y_basis)\n",
    "mbqc.measure('5', Y_basis)\n",
    "mbqc.measure('6', Y_basis)\n",
    "mbqc.measure('8', Y_basis)\n",
    "mbqc.measure('9', X_basis)\n",
    "mbqc.measure('10', X_basis)\n",
    "mbqc.measure('11', X_basis)\n",
    "mbqc.measure('12', Y_basis)\n",
    "mbqc.measure('13', X_basis)\n",
    "mbqc.measure('14', X_basis)\n",
    "\n",
    "# 计算副产品的系数\n",
    "cx = mbqc.sum_outcomes(['2', '3', '5', '6'])\n",
    "tx = mbqc.sum_outcomes(['2', '3', '8', '10', '12', '14'])\n",
    "cz = mbqc.sum_outcomes(['1', '3', '4', '5', '8', '9', '11'], 1)\n",
    "tz = mbqc.sum_outcomes(['9', '11', '13'])\n",
    "\n",
    "# 对测量后的量子态进行副产品修正\n",
    "mbqc.correct_byproduct('X', '7', cx)\n",
    "mbqc.correct_byproduct('X', '15', tx)\n",
    "mbqc.correct_byproduct('Z', '7', cz)\n",
    "mbqc.correct_byproduct('Z', '15', tz)\n",
    "\n",
    "# 读取经典输出结果\n",
    "classical_output = mbqc.get_classical_output()\n",
    "# 读取量子输出结果\n",
    "quantum_output = mbqc.get_quantum_output()\n",
    "\n",
    "# 构造预期的量子态\n",
    "vector_std = matmul(to_tensor(cnot_gate()), input_psi)\n",
    "state_std = State(vector_std, ['7', '15'])\n",
    "\n",
    "# 与预期的量子态作比较\n",
    "compare_by_vector(quantum_output, state_std)"
   ],
   "outputs": [],
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 欢迎使用 MBQC 模块！\n",
    "\n",
    "在介绍完上述 MBQC 计算模型以及相关模块的简单示例之后，我们建议您参阅下面的教程进一步学习。\n",
    "\n",
    "- [基于测量的量子近似优化算法](QAOA_CN.ipynb)\n",
    "- [MBQC 模型下求解多项式组合优化问题](PUBO_CN.ipynb)\n",
    "\n",
    "我们开发的 MBQC 模块作为量桨平台的新功能，它所能做的远不止上述这几个例子，我们真诚希望您可以使用 MBQC 模型和我们开发的模块去探索更多有趣的实例！关于 MBQC 计算模型本身更为详细的学习，有兴趣的读者可以参考 [15,16]。"
   ],
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": [
    "---\n",
    "\n",
    "## 参考文献\n",
    "\n",
    "[1] Deutsch, David Elieser. \"Quantum computational networks.\" [Proceedings of the Royal Society of London. A. 425.1868 (1989): 73-90.](https://royalsocietypublishing.org/doi/abs/10.1098/rspa.1989.0099)\n",
    "\n",
    "[2] Barenco, Adriano, et al. \"Elementary gates for quantum computation.\" [Physical review A 52.5 (1995): 3457.](https://journals.aps.org/pra/abstract/10.1103/PhysRevA.52.3457)\n",
    "\n",
    "[3] Gottesman, Daniel, and Isaac L. Chuang. \"Demonstrating the viability of universal quantum computation using teleportation and single-qubit operations.\" [Nature 402.6760 (1999): 390-393.](https://www.nature.com/articles/46503?__hstc=13887208.d9c6f9c40e1956d463f0af8da73a29a7.1475020800048.1475020800050.1475020800051.2&__hssc=13887208.1.1475020800051&__hsfp=1773666937)\n",
    "\n",
    "[4] Nielsen, Michael A. \"Quantum computation by measurement and quantum memory.\" [Physics Letters A 308.2-3 (2003): 96-100.](https://www.sciencedirect.com/science/article/abs/pii/S0375960102018030)\n",
    "\n",
    "[5] Leung, Debbie W. \"Quantum computation by measurements.\" [International Journal of Quantum Information 2.01 (2004): 33-43.](https://www.worldscientific.com/doi/abs/10.1142/S0219749904000055)\n",
    "\n",
    "[6] Robert Raussendorf, et al. \"A one-way quantum computer.\" [Physical Review Letters 86.22 (2001): 5188.](https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.86.5188)\n",
    "\n",
    "[7] Raussendorf, Robert, and Hans J. Briegel. \"Computational model underlying the one-way quantum computer.\" [Quantum Information & Computation 2.6 (2002): 443-486.](https://dl.acm.org/doi/abs/10.5555/2011492.2011495)\n",
    "\n",
    "[8] Robert Raussendorf, et al. \"Measurement-based quantum computation on cluster states.\" [Physical Review A 68.2 (2003): 022312.](https://journals.aps.org/pra/abstract/10.1103/PhysRevA.68.022312)\n",
    "\n",
    "[9] Briegel, Hans J., et al. \"Measurement-based quantum computation.\" [Nature Physics 5.1 (2009): 19-26.](https://www.nature.com/articles/nphys1157)\n",
    "\n",
    "[10] Aliferis, Panos, and Debbie W. Leung. \"Computation by measurements: a unifying picture.\" [Physical Review A 70.6 (2004): 062314.](https://journals.aps.org/pra/abstract/10.1103/PhysRevA.70.062314)\n",
    "\n",
    "[11] Broadbent, Anne, et al. \"Universal blind quantum computation.\" [2009 50th Annual IEEE Symposium on Foundations of Computer Science. IEEE, 2009.](https://arxiv.org/abs/0807.4154)\n",
    "\n",
    "[12] Morimae, Tomoyuki. \"Verification for measurement-only blind quantum computing.\" [Physical Review A 89.6 (2014): 060302.](https://journals.aps.org/pra/abstract/10.1103/PhysRevA.89.060302)\n",
    "\n",
    "[13] Larsen, Mikkel V., et al. \"Deterministic generation of a two-dimensional cluster state.\" [Science 366.6463 (2019): 369-372.](https://science.sciencemag.org/content/366/6463/369)\n",
    "\n",
    "[14] Asavanant, Warit, et al. \"Generation of time-domain-multiplexed two-dimensional cluster state.\" [Science 366.6463 (2019): 373-376.](https://science.sciencemag.org/content/366/6463/373)\n",
    "\n",
    "[15] Richard Jozsa, et al. \"An introduction to measurement based quantum computation.\" [arXiv:quant-ph/0508124](https://arxiv.org/abs/quant-ph/0508124v2)\n",
    "\n",
    "[16] Nielsen, Michael A. \"Cluster-state quantum computation.\" [Reports on Mathematical Physics 57.1 (2006): 147-161.](https://www.sciencedirect.com/science/article/abs/pii/S0034487706800145)\n",
    "\n",
    "[17] Nielsen, Michael A., and Isaac Chuang. \"Quantum computation and quantum information.\"[Cambridge university press (2010).](https://www.cambridge.org/core/books/quantum-computation-and-quantum-information/01E10196D0A682A6AEFFEA52D53BE9AE)\n",
    "\n",
    "[18] Danos, Vincent, et al. \"The measurement calculus.\" [Journal of the ACM (JACM) 54.2 (2007): 8-es.](https://dl.acm.org/doi/abs/10.1145/1219092.1219096)"
   ],
   "metadata": {}
  }
 ],
 "metadata": {
  "interpreter": {
   "hash": "07efdcd4b820c98a756949507a4d29d7862823915ec7477944641bea022f4f62"
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.10"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {
    "height": "calc(100% - 180px)",
    "left": "10px",
    "top": "150px",
    "width": "268.448px"
   },
   "toc_section_display": true,
   "toc_window_display": false
  },
  "toc-autonumbering": false,
  "toc-showcode": false,
  "toc-showmarkdowntxt": false,
  "toc-showtags": false,
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}